﻿using Senparc.Weixin.MP.TenPayLibV3;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Xml.Linq;

namespace MxWeiXinPF.WeiXinComm
{
   public  class WXPayHelper
    {

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            if (errors == SslPolicyErrors.None)
                return true;
            return false;
        }



        /*
         * 退款的返回值xml字符串：成功的：
         * <xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wxd745017dc584cdc9]]></appid>
<mch_id><![CDATA[10011937]]></mch_id>
<nonce_str><![CDATA[B53UimP60pSCTLG7]]></nonce_str>
<sign><![CDATA[26FB85BD6F7FE4A87D889714B1D68539]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<transaction_id><![CDATA[4003532001201703305233022203]]></transaction_id>
<out_trade_no><![CDATA[J17033023501819]]></out_trade_no>
<out_refund_no><![CDATA[tk11_1750102350142942]]></out_refund_no>
<refund_id><![CDATA[2003532001201704101019409490]]></refund_id>
<refund_channel><![CDATA[]]></refund_channel>
<refund_fee>3</refund_fee>
<coupon_refund_fee>0</coupon_refund_fee>
<total_fee>4</total_fee>
<cash_fee>4</cash_fee>
<coupon_refund_count>0</coupon_refund_count>
<cash_refund_fee>3</cash_refund_fee>
</xml>
*************************************************************
* 失败：
* <xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
  <appid><![CDATA[wxd745017dc584cdc9]]></appid>
  <mch_id><![CDATA[10011937]]></mch_id>
  <nonce_str><![CDATA[01azoqye0UKzoey3]]></nonce_str>
  <sign><![CDATA[27C10609C3683CA5A144176AD1435391]]></sign>
  <result_code><![CDATA[FAIL]]></result_code>
  <err_code><![CDATA[REFUND_FEE_INVALID]]></err_code>
  <err_code_des><![CDATA[累计退款金额大于支付金额]]></err_code_des>
</xml>

         * **/
        /// <summary>
        /// 退款
        /// 返回值字典值：
        /// </summary>
        /// <param name="orderEntity">支付的订单具体信息,包括订单号等</param>
        /// <param name="refund_fee_money">退款金额(单位分)</param>
        public Dictionary<string,string>  Refund( Model.orders orderEntity,int refund_fee_money)
        {
            Dictionary<string, string> ret = new Dictionary<string, string>();

            BLL.wx_payment_refund_record refundBll = new BLL.wx_payment_refund_record();
            Model.wx_payment_refund_record refundModel = new Model.wx_payment_refund_record();

            try
            {
                string out_refund_no = "tk" + orderEntity.wid + "_" + DateTime.Now.ToString("yymmddHHmmss") + TenPayV3Util.BuildRandomStr(4);

                #region 实例化数据实体

                refundModel.create_time = DateTime.Now;
                refundModel.order_no = orderEntity.order_no;
                refundModel.wid = orderEntity.wid;
                refundModel.modelName = orderEntity.modelName;
                refundModel.modelCode = orderEntity.modelCode;
                refundModel.modelActionName = orderEntity.modelActionName;
                refundModel.modelActionId = orderEntity.modelActionId;
                refundModel.orderSubject = orderEntity.orderSubject;
                refundModel.trade_no = orderEntity.trade_no;
                refundModel.out_refund_no = out_refund_no;
                refundModel.refund_fee = refund_fee_money;
                refundModel.refund_status = 0;
                #endregion

                string nonceStr = TenPayV3Util.GetNoncestr();
                RequestHandler packageReqHandler = new RequestHandler(null);

                BLL.wx_userweixin bll = new BLL.wx_userweixin();
                Model.wx_userweixin weixinModel = bll.GetModel(orderEntity.wid.Value);

                BLL.wx_payment_wxpay weixinPayBLL = new BLL.wx_payment_wxpay();
                Model.wx_payment_wxpay weixinPayModel = weixinPayBLL.GetModelByWid(orderEntity.wid.Value);

                if (weixinPayModel == null || weixinPayModel == null)
                {
                    ret.Add("status", "0");
                    ret.Add("msg", "weixinPayModel或者weixinPayModel没有取到数据");
                    return ret;
                }

                //设置package订单参数
                packageReqHandler.SetParameter("appid", weixinModel.AppId); //公众账号ID
                packageReqHandler.SetParameter("mch_id", weixinPayModel.mch_id); //商户号
                packageReqHandler.SetParameter("out_trade_no", orderEntity.order_no); //填入商家订单号
                packageReqHandler.SetParameter("out_refund_no", out_refund_no); //填入退款订单号
                packageReqHandler.SetParameter("total_fee", ((int)(orderEntity.order_amount*100)).ToString()); //填入总金额
                packageReqHandler.SetParameter("refund_fee", refund_fee_money.ToString());  //填入退款金额
                packageReqHandler.SetParameter("op_user_id", weixinPayModel.mch_id);   //操作员Id，默认就是商户号
                packageReqHandler.SetParameter("nonce_str", nonceStr);   //随机字符串
                string sign = packageReqHandler.CreateMd5Sign("key", weixinPayModel.paykey);
                packageReqHandler.SetParameter("sign", sign);  //签名
                                                               //退款需要post的数据
                string data = packageReqHandler.ParseXML();

                //退款接口地址
                string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
                //本地或者服务器的证书位置（证书在微信支付申请成功发来的通知邮件中）必须有请求的上下文，不然会报错
                string cert = HttpContext.Current.Server.MapPath(weixinPayModel.certInfoPath);
                //私钥（在安装证书时设置）
                string password = weixinPayModel.cerInfoPwd;
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                //调用证书
                X509Certificate2 cer = new X509Certificate2(cert, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

                #region 发起post请求
                HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
                webrequest.ClientCertificates.Add(cer);
                webrequest.Method = "post";

                byte[] postdatabyte = Encoding.UTF8.GetBytes(data);
                webrequest.ContentLength = postdatabyte.Length;
                Stream stream;
                stream = webrequest.GetRequestStream();
                stream.Write(postdatabyte, 0, postdatabyte.Length);
                stream.Close();

                HttpWebResponse httpWebResponse = (HttpWebResponse)webrequest.GetResponse();
                StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
                string responseContent = streamReader.ReadToEnd();
                #endregion

                var res = XDocument.Parse(responseContent);

                if (res != null && res.Element("xml").Element("result_code") != null)
                {
                     
                    if (res.Element("xml").Element("result_code").Value.ToLower() == "success")
                    {
                        //退款成功
                        ret.Add("status", "1");
                        ret.Add("msg", "退款成功");
                        ret.Add("out_refund_no", out_refund_no);
                        refundModel.refund_status = 1;

                        return ret;
                    }
                    else
                    {
                        //退款失败
                        string err_code = res.Element("xml").Element("err_code").Value;
                        string err_code_des = res.Element("xml").Element("err_code_des").Value;
                        ret.Add("status", "0");
                        ret.Add("msg", "退款失败：err_code=" + err_code + ",err_code_des=" + err_code_des);
                        ret.Add("out_refund_no", "");
                        refundModel.refund_status =0;
                        refundModel.err_code = err_code;
                        refundModel.err_code_des = err_code_des;
                        return ret;
                    }
                }
                else
                {
                    //返回的xml有问题的处理
                    ret.Add("status", "0");
                    ret.Add("msg", "退款失败：返回的xml有问题的处理");
                    ret.Add("out_refund_no", "");

                    refundModel.refund_status = 0;
                    refundModel.err_code = "pt1000";
                    refundModel.err_code_des = "退款失败：返回的xml有问题的处理";
                    return ret;
                }
            }
            catch (Exception ex)
            {
                ret.Add("status", "0");
                ret.Add("msg", "退款失败：try,catch报异常：" + ex.Message);
                ret.Add("out_refund_no", "");
                refundModel.refund_status = 0;
                refundModel.err_code = "pt1001";
                refundModel.err_code_des = "try,catch报异常："+ex.Message;
            }
            finally
            {
                refundBll.Add(refundModel);
            }
            return ret;

           
        }//end:function


    }
}
